using System;
using System.Reflection;

namespace Volo.Abp;

[Serializable]
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)]
public class RemoteServiceAttribute : Attribute //TODO: Can we move this to another package (with IRemoteService)?
{
    /// <summary>
    /// Default: true.
    /// </summary>
    public bool IsEnabled { get; set; }

    /// <summary>
    /// Default: true.
    /// </summary>
    public bool IsMetadataEnabled { get; set; }

    /// <summary>
    /// Group name of the remote service.
    /// Group names of all services of a module expected to be the same.
    /// This name is also used to distinguish the service endpoint of this group.
    /// </summary>
    public string Name { get; set; } = default!;

    public RemoteServiceAttribute(bool isEnabled = true)
    {
        IsEnabled = isEnabled;
        IsMetadataEnabled = true;
    }

    public virtual bool IsEnabledFor(Type type)
    {
        return IsEnabled;
    }

    public virtual bool IsEnabledFor(MethodInfo method)
    {
        return IsEnabled;
    }

    public virtual bool IsMetadataEnabledFor(Type type)
    {
        return IsMetadataEnabled;
    }

    public virtual bool IsMetadataEnabledFor(MethodInfo method)
    {
        return IsMetadataEnabled;
    }

    public static bool IsExplicitlyEnabledFor(Type type)
    {
        var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
        return remoteServiceAttr != null && remoteServiceAttr.IsEnabledFor(type);
    }

    public static bool IsExplicitlyDisabledFor(Type type)
    {
        var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
        return remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(type);
    }

    public static bool IsMetadataExplicitlyEnabledFor(Type type)
    {
        var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
        return remoteServiceAttr != null && remoteServiceAttr.IsMetadataEnabledFor(type);
    }

    public static bool IsMetadataExplicitlyDisabledFor(Type type)
    {
        var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
        return remoteServiceAttr != null && !remoteServiceAttr.IsMetadataEnabledFor(type);
    }

    public static bool IsMetadataExplicitlyDisabledFor(MethodInfo method)
    {
        var remoteServiceAttr = method.GetSingleAttributeOrNull<RemoteServiceAttribute>();
        return remoteServiceAttr != null && !remoteServiceAttr.IsMetadataEnabledFor(method);
    }

    public static bool IsMetadataExplicitlyEnabledFor(MethodInfo method)
    {
        var remoteServiceAttr = method.GetSingleAttributeOrNull<RemoteServiceAttribute>();
        return remoteServiceAttr != null && remoteServiceAttr.IsMetadataEnabledFor(method);
    }
}
